/**
 *    @file       buffermgr.h
 *
 *    @brief      
 *    @details
 *
 *    @version    1.0
 *    @date       12/09/2012 07:16:50 PM
 *
 *    @author     Theophilus, wangtf418@gmail.com
 */
#ifndef _BF_BUFFERMGR_H_
#define _BF_BUFFERMGR_H_

#include <string>
#include "comdef.h"
#include "endianness_trans.h"

class buffermgr : public endianness_trans
{
public:
	buffermgr()
		: m_buf(NULL), m_buf_len(0), m_offset(0), m_delete_flag(1)
	{

	}

	buffermgr(bf_char_t *buf, bf_size_t buf_len, bf_int_t delete_flag = 1, bf_int_t trans_flag = 1)
		: endianness_trans(trans_flag), 
		m_buf(buf), m_buf_len(buf_len), m_offset(0), m_delete_flag(delete_flag)
	{

	}

	virtual ~buffermgr()
	{
		if (m_delete_flag && m_buf)
		{
			delete [] m_buf;
			m_buf_len = 0;
			m_offset = 0;
		}
	}

public:
	inline void set_delete_flag(bf_int_t delete_flag) {m_delete_flag = delete_flag;}
	inline bf_int_t get_delete_flag() {return m_delete_flag;}

public:
	inline void attach_buf(bf_char_t *buf, bf_size_t buf_len)
	{
		m_buf = buf;
		m_buf_len = buf_len;
		m_offset = 0;
	}

	inline void detach_buf()
	{
		m_buf = NULL;
		m_buf_len = 0;
		m_offset = 0;
	}

	inline void reset_buf(bf_char_t *buf, bf_size_t buf_len)
	{
		if (m_buf && m_delete_flag)
		{
			delete [] m_buf;
		}

		m_buf = buf;
		m_buf_len = buf_len;
		m_offset = 0;
	}

public:
	inline bf_char_t* get_buf() {return m_buf;}
	inline bf_size_t get_buflen() {return m_buf_len;}
	inline void set_buf(bf_char_t *buf, bf_size_t buf_len, bf_size_t offset = 0)
	{
		m_buf = buf;
		m_buf_len = buf_len;
		m_offset = offset;
	}

public:
	inline bf_size_t get_offset() {return m_offset;}
	inline void set_offset(bf_size_t offset) {m_offset = offset;}

public:
	inline bf_int_t valid_check()
	{
		if (!m_buf || m_offset > m_buf_len)
		{
			return BF_ERROR;
		}
		return BF_OK;
	}

	inline bf_int_t put_int8(bf_int8_t num)
	{
		if (m_offset + BF_SIZE_OF_INT8 > m_buf_len)
		{
			return BF_ERROR;
		}
		//num = trans_int8(num); //no need
		memcpy(m_buf + m_offset, &num, BF_SIZE_OF_INT8);
		m_offset += BF_SIZE_OF_INT8;
		return BF_OK;
	}

	inline bf_int_t put_int16(bf_int16_t num)
	{
		if (m_offset + BF_SIZE_OF_INT16 > m_buf_len)
		{
			return BF_ERROR;
		}
		num = trans_int16(num);
		memcpy(m_buf + m_offset, &num, BF_SIZE_OF_INT16);
		m_offset += BF_SIZE_OF_INT16;
		return BF_OK;
	}

	inline bf_int_t put_int32(bf_int32_t num)
	{
		if (m_offset + BF_SIZE_OF_INT32 > m_buf_len)
		{
			return BF_ERROR;
		}
		num = trans_int32(num);
		memcpy(m_buf + m_offset, &num, BF_SIZE_OF_INT32);
		m_offset += BF_SIZE_OF_INT32;
		return BF_OK;
	}

	inline bf_int_t put_int64(bf_int64_t num)
	{
		if (m_offset + BF_SIZE_OF_INT64 > m_buf_len)
		{
			return BF_ERROR;
		}
		num = trans_int64(num);
		memcpy(m_buf + m_offset, &num, BF_SIZE_OF_INT64);
		m_offset += BF_SIZE_OF_INT64;
		return BF_OK;
	}

	inline bf_int_t put_buf_str(const bf_char_t *buf, bf_size_t buf_len)
	{
		if (!buf || buf_len > m_buf_len || m_offset + buf_len > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(m_buf + m_offset, buf, buf_len);
		m_offset += buf_len;
		return BF_OK;
	}

	inline bf_int_t put_string(const std::string &str)
	{
		bf_size_t str_len = str.length();
		if (m_offset + BF_SIZE_OF_INT32 + str_len > m_buf_len)
		{
			return BF_ERROR;
		}
		bf_int32_t str_len_tmp = trans_int32(str_len);
		memcpy(m_buf + m_offset, &str_len_tmp, BF_SIZE_OF_INT32);
		m_offset += BF_SIZE_OF_INT32;
		if (str_len > 0)
		{
			memcpy(m_buf + m_offset, str.c_str(), str_len);
			m_offset += str_len;
		}
		return BF_OK;
	}

	inline bf_int_t get_int8(bf_int8_t &num)
	{
		if (m_offset + BF_SIZE_OF_INT8 > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(&num, m_buf + m_offset, BF_SIZE_OF_INT8);
		//num = trans_int8(num); //no need
		m_offset += BF_SIZE_OF_INT8;
		return BF_OK;
	}

	inline bf_int_t get_int16(bf_int16_t &num)
	{
		if(m_offset + BF_SIZE_OF_INT32 > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(&num, m_buf + m_offset, BF_SIZE_OF_INT16);
		num = trans_int16(num);
		m_offset += BF_SIZE_OF_INT16;
		return BF_OK;
	}

	inline bf_int_t get_int32(bf_int32_t &num)
	{
		if (m_offset + BF_SIZE_OF_INT32 > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(&num, m_buf + m_offset, BF_SIZE_OF_INT32);
		num = trans_int32(num);
		m_offset += BF_SIZE_OF_INT32;
		return BF_OK;
	}

	inline bf_int_t get_int64(bf_int64_t &num)
	{
		if (m_offset + BF_SIZE_OF_INT64 > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(&num, m_buf + m_offset, BF_SIZE_OF_INT64);
		num = trans_int64(num);
		m_offset += BF_SIZE_OF_INT64;
		return BF_OK;
	}

	inline bf_int_t get_buf_str(bf_char_t *buf, bf_size_t buf_len)
	{
		if (!buf || m_offset + buf_len > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(buf, m_buf + m_offset, buf_len);
		m_offset += buf_len;
		return BF_OK;
	}

	inline bf_int_t get_string(std::string &str)
	{
		bf_int32_t str_len;
		if (m_offset + BF_SIZE_OF_INT32 > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(&str_len, m_buf + m_offset, BF_SIZE_OF_INT32);
		str_len = trans_int32(str_len);
		m_offset += BF_SIZE_OF_INT32;
		if (str_len < 0 || m_offset + str_len > m_buf_len)
		{
			m_offset -= BF_SIZE_OF_INT32;
			return BF_ERROR;
		}
		m_offset += str_len;
		return BF_OK;
	}

	inline bf_int_t get_int8(bf_size_t offset, bf_int8_t &num)
	{
		if (offset + BF_SIZE_OF_INT8 > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(&num, m_buf + offset, BF_SIZE_OF_INT8);
		//num = trans_int8(num); //no need
		return BF_OK;
	}

	inline bf_int_t get_int16(bf_size_t offset, bf_int16_t &num)
	{
		if(offset + BF_SIZE_OF_INT32 > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(&num, m_buf + offset, BF_SIZE_OF_INT16);
		num = trans_int16(num);
		return BF_OK;
	}

	inline bf_int_t get_int32(bf_size_t offset, bf_int32_t &num)
	{
		if (offset + BF_SIZE_OF_INT32 > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(&num, m_buf + offset, BF_SIZE_OF_INT32);
		num = trans_int32(num);
		return BF_OK;
	}

	inline bf_int_t get_int64(bf_size_t offset, bf_int64_t &num)
	{
		if (offset + BF_SIZE_OF_INT64 > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(&num, m_buf + offset, BF_SIZE_OF_INT64);
		num = trans_int64(num);
		return BF_OK;
	}

	inline bf_int_t get_buf_str(bf_size_t offset, bf_char_t *buf, bf_size_t buf_len)
	{
		if (!buf || offset + buf_len > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(buf, m_buf + offset, buf_len);
		return BF_OK;
	}

	inline bf_int_t get_string(bf_size_t offset, std::string &str)
	{
		bf_int32_t str_len;
		if (offset + BF_SIZE_OF_INT32 > m_buf_len)
		{
			return BF_ERROR;
		}
		memcpy(&str_len, m_buf + offset, BF_SIZE_OF_INT32);
		str_len = trans_int32(str_len);
		offset += BF_SIZE_OF_INT32;
		if (str_len < 0 || offset + (bf_size_t)str_len > m_buf_len)
		{
			return BF_ERROR;
		}
		return BF_OK;
	}

public:
	inline bf_int_t put_int8(bf_uint8_t num) {return put_int8((bf_int8_t)num);}
	inline bf_int_t put_int16(bf_uint16_t num) {return put_int16((bf_int16_t)num);}
	inline bf_int_t put_int32(bf_uint32_t num) {return put_int32((bf_int32_t)num);}
	inline bf_int_t put_int64(bf_uint64_t num) {return put_int64((bf_int64_t)num);}

	inline bf_int_t get_int8(bf_uint8_t &num) {return get_int8((bf_int8_t&)num);}
	inline bf_int_t get_int16(bf_uint16_t &num) {return get_int16((bf_int16_t&)num);}
	inline bf_int_t get_int32(bf_uint32_t &num) {return get_int32((bf_int32_t&)num);}
	inline bf_int_t get_int64(bf_uint64_t &num) {return get_int64((bf_int64_t&)num);}

	inline bf_int_t get_int8(bf_size_t offset, bf_uint8_t &num) {return get_int8(offset, (bf_int8_t&)num);}
	inline bf_int_t get_int16(bf_size_t offset, bf_uint16_t &num) {return get_int16(offset, (bf_int16_t&)num);}
	inline bf_int_t get_int32(bf_size_t offset, bf_uint32_t &num) {return get_int32(offset, (bf_int32_t&)num);}
	inline bf_int_t get_int64(bf_size_t offset, bf_uint64_t &num) {return get_int64(offset, (bf_int64_t&)num);}

protected:
	bf_char_t *m_buf;
	bf_size_t m_buf_len;
	bf_size_t m_offset;
	bf_int_t m_delete_flag;

};

#endif

